﻿using FySystem.Data.OrmA.Attributes;
using FySystem.Data.OrmA.Ext;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace FySystem.Data.OrmA.Reflection
{
    class ReflectionManager
    {
        /// <summary>
        /// 实体类的反射缓存
        /// </summary>
        private static Dictionary<string, ReflectionInfo> _caches = new Dictionary<string, ReflectionInfo>();
        private static Type _typeTableAttribute = typeof(FyTableAttribute);
        private static Type _typeColumnAttribute = typeof(FyColumnAttribute);

        /// <summary>
        /// 反射实体类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        internal static ReflectionInfo ReflectionModel<T>()
        {
            ReflectionInfo res = null;
            try
            {
                Type t = typeof(T);
                string key = t.FullName;
                lock (_caches)
                {
                    if (_caches.ContainsKey(key))
                        res = _caches[key];
                }

                if (res == null)
                {
                    //如果缓存中不存在
                    res = new ReflectionInfo();
                    ColumnProperty primaryKey = null;

                    res.ModelType = t;
                    res.Table = GetTableName(t.GetCustomAttributes(_typeTableAttribute, true));
                    res.Mapping = Mapping(t.GetProperties(), ref primaryKey);
                    res.PrimaryKey = primaryKey;

                    //加入缓存
                    lock (_caches)
                        _caches.Add(key, res);
                }
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 对属性按照名字进行关联
        /// </summary>
        /// <param name="propertyInfos"></param>
        /// <param name="primaryKey"></param>
        /// <returns></returns>
        private static Dictionary<string, ColumnProperty> Mapping(PropertyInfo[] propertyInfos, ref ColumnProperty primaryKey)
        {
            Dictionary<string, ColumnProperty> res = null;
            try
            {
                if (propertyInfos.IsNullOrEmpty())
                    return res;

                res = new Dictionary<string, ColumnProperty>();

                foreach (var property in propertyInfos)
                {
                    //加入属性
                    ColumnProperty item = new ColumnProperty();
                    item.PropertyInfo = property;

                    //加入对应的数据库列信息
                    object[] columnAttrs = property.GetCustomAttributes(_typeColumnAttribute, true);

                    if (columnAttrs.IsNullOrEmpty() == false)
                    {
                        FyColumnAttribute columnAttr = (FyColumnAttribute)columnAttrs[0];
                        if (columnAttr.IsPrimaryKey == true)
                        {
                            primaryKey = item;
                        }

                        columnAttr.MappingColumn = string.IsNullOrWhiteSpace(columnAttr.MappingColumn) ? property.Name : columnAttr.MappingColumn;
                        item.Column = columnAttr;
                        item.IsDbColumn = true;
                    }
                    else
                    {
                        item.Column = new FyColumnAttribute();
                        item.Column.IsPrimaryKey = false;
                        item.Column.MappingColumn = property.Name;
                        item.IsDbColumn = false;
                    }
                    res.Add(item.Column.MappingColumn.ToUpper(), item);
                }
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 获取实体的表名
        /// </summary>
        /// <param name="fyTableAttributes"></param>
        /// <returns></returns>
        private static FyTableAttribute GetTableName(object[] fyTableAttributes)
        {
            FyTableAttribute res = null;
            try
            {
                if (fyTableAttributes != null)
                {
                    if (fyTableAttributes.Length > 0)
                    {
                        res = (FyTableAttribute)fyTableAttributes[0];
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }
    }
}
